﻿using System.Linq.Expressions;
using wwl.Contract.Dtos.Common;
using wwl.Domain.Entities.Common;

namespace wwl.Contract.Interfaces.Common
{
  /// <summary>
  /// 数据上下文包装器接口，统一封装数据访问层的核心操作（查询、增删改、事务提交）
  /// 屏蔽底层 ORM 框架细节（如 EF Core），提供跨实体的通用数据操作能力
  /// 支持所有继承自 <see cref="BaseEntity"/> 的领域实体，确保操作一致性
  /// </summary>
  public interface IEfWrapper
  {
    /// <summary>
    /// 获取指定实体的可查询集合（开启变更跟踪）
    /// </summary>
    /// <typeparam name="T">领域实体类型，必须继承自 <see cref="BaseEntity"/></typeparam>
    /// <returns>可拼接查询条件的 <see cref="IQueryable{T}"/> 对象</returns>
    /// <remarks>
    /// 变更跟踪会监控实体状态变化，适合查询后需要修改、删除实体的场景
    /// 性能略低于无跟踪查询，不建议用于高频只读场景
    /// </remarks>
    IQueryable<T> Query<T>() where T : BaseEntity;

    /// <summary>
    /// 获取指定实体的可查询集合（关闭变更跟踪）
    /// </summary>
    /// <typeparam name="T">领域实体类型，必须继承自 <see cref="BaseEntity"/></typeparam>
    /// <returns>可拼接查询条件的 <see cref="IQueryable{T}"/> 对象</returns>
    /// <remarks>
    /// 无跟踪查询不监控实体状态，内存消耗更低、性能更优
    /// 适用于仅读取数据的场景（如列表展示、数据导出），查询后修改实体需手动附加到上下文
    /// </remarks>
    IQueryable<T> QueryNoTracking<T>() where T : BaseEntity;

    /// <summary>
    /// 根据 ID 异步查询单个指定类型的实体
    /// </summary>
    /// <typeparam name="T">领域实体类型，必须继承自 <see cref="BaseEntity"/></typeparam>
    /// <param name="id">实体唯一标识（对应 <see cref="BaseEntity.Id"/>）</param>
    /// <returns>找到则返回实体对象，未找到则返回 null（可空类型避免空引用异常）</returns>
    Task<T?> GetByIdAsync<T>(string id) where T : BaseEntity;

    /// <summary>
    /// 异步新增指定类型的实体
    /// </summary>
    /// <typeparam name="T">领域实体类型，必须继承自 <see cref="BaseEntity"/></typeparam>
    /// <param name="entity">待新增的实体对象（需包含完整业务字段）</param>
    /// <returns>新增后的实体（可能包含数据库自动生成的 ID、创建时间等字段）</returns>
    /// <remarks>
    /// 此方法仅将实体添加到数据上下文，未提交到数据库
    /// 需调用 <see cref="SaveChangesAsync()"/> 方法完成最终持久化
    /// </remarks>
    Task<T> AddAsync<T>(T entity) where T : BaseEntity;

    /// <summary>
    /// 异步更新指定类型的实体
    /// </summary>
    /// <typeparam name="T">领域实体类型，必须继承自 <see cref="BaseEntity"/></typeparam>
    /// <param name="entity">待更新的实体对象（需包含有效 ID 以定位数据）</param>
    /// <returns>更新后的实体（反映最新状态）</returns>
    /// <remarks>
    /// 此方法仅标记实体为修改状态，未提交到数据库
    /// 需调用 <see cref="SaveChangesAsync()"/> 方法完成最终更新
    /// </remarks>
    Task<T> UpdateAsync<T>(T entity) where T : BaseEntity;

    /// <summary>
    /// 异步物理删除指定类型的实体（从数据库彻底移除记录）
    /// </summary>
    /// <typeparam name="T">领域实体类型，必须继承自 <see cref="BaseEntity"/></typeparam>
    /// <param name="id">实体唯一标识</param>
    /// <returns>删除成功返回 true；实体不存在或删除失败返回 false</returns>
    /// <remarks>
    /// 物理删除不可逆，适用于无需保留历史数据的场景
    /// 需调用 <see cref="SaveChangesAsync()"/> 方法使删除生效
    /// </remarks>
    Task<bool> DeleteAsync<T>(string id) where T : BaseEntity;

    /// <summary>
    /// 异步逻辑删除指定类型的实体（标记删除状态，不实际移除记录）
    /// </summary>
    /// <typeparam name="T">领域实体类型，必须继承自 <see cref="BaseEntity"/></typeparam>
    /// <param name="id">实体唯一标识</param>
    /// <returns>标记删除成功返回 true；实体不存在或标记失败返回 false</returns>
    /// <remarks>
    /// 通常通过设置实体的 IsDeleted 等字段实现，支持数据恢复和历史查询
    /// 需调用 <see cref="SaveChangesAsync()"/> 方法使标记生效
    /// </remarks>
    Task<bool> SoftDeleteAsync<T>(string id) where T : BaseEntity;

    /// <summary>
    /// 异步提交所有未保存的操作（新增、更新、删除）到数据库，实现事务性处理
    /// </summary>
    /// <returns>受影响的数据库记录行数（用于验证操作生效数量）</returns>
    /// <remarks>
    /// 采用事务机制：所有操作要么全部成功提交，要么全部失败回滚，保证数据一致性
    /// 多实体联合操作（如同时新增租户和关联角色）必须通过此方法统一提交
    /// </remarks>
    Task<int> SaveChangesAsync();

    /// <summary>
    /// 异步执行指定类型实体的分页查询，支持自定义筛选条件
    /// </summary>
    /// <typeparam name="T">领域实体类型，必须继承自 <see cref="BaseEntity"/></typeparam>
    /// <param name="request">分页请求参数（包含页码 PageIndex、每页条数 PageSize）</param>
    /// <param name="filter">可选筛选条件表达式（如 t => t.IsActive），为 null 时查询所有符合条件的实体</param>
    /// <returns>
    /// 分页结果对象 <see cref="PagedResult{T}"/>，包含：
    /// - Total：符合筛选条件的总记录数
    /// - Items：当前页的实体列表
    /// </returns>
    /// <remarks>
    /// 内部自动处理分页逻辑（Skip 跳过前序数据 + Take 截取当前页数据）
    /// 默认采用无跟踪查询提升性能，适合列表展示等只读场景
    /// </remarks>
    Task<PagedResult<T>> GetPagedAsync<T>(PagedRequest request,
        Expression<Func<T, bool>>? filter = null) where T : BaseEntity;
  }
}